
#include <ArchitectureDependent/LegacyBIOS/MemoryPlan.hpp>
#include <Kernel/MemoryManagement/Buddy.hpp>
#include <Kernel/MemoryManagement/UsedMemory.hpp>
#include <DataStructure/RedBlackTree.hpp>

extern "C" CALLCONV ULONG getPageTableEntry(void *addr);

const unsigned itemsUsedMemory = (0x1000 - sizeof(unsigned)) /
			sizeof(RedBlackNode<MemorySize>);

inline UsedMemory *getHead(void *addr){
	return reinterpret_cast<UsedMemory*>(
			reinterpret_cast<ULONG>(addr) & ~0xFFF);
}

CALLCONV bool isFree(void *addr){
	ULONG pagingEntryPointer = getPageTableEntry(addr);
	ULONG pagingEntry = *reinterpret_cast<ULONG*>(pagingEntryPointer & ~3);
	return (pagingEntry & 0x801) == 1;
}

CALLCONV bool setBusyDMA(void *addr, UnsignedInteger numPages){
	Buddy<0x100,9> *dma = (Buddy<0x100,9>*)MEMORY_STRUCTURE;
	Buddy<0x100,19> *main = (Buddy<0x100,19>*)(MEMORY_STRUCTURE +
			sizeof(Buddy<0x100,9>));
	RedBlackTree<MemorySize> *dmaBusy = (RedBlackTree<MemorySize>*)(
			MEMORY_STRUCTURE + sizeof(Buddy<0x100,9>) +
			sizeof(Buddy<0x100,19>));
	RedBlackTree<MemorySize> *mainBusy = dmaBusy + 1;
	LinkedList<UINT8> *emptyItems = reinterpret_cast<LinkedList<UINT8>*>(
			mainBusy + 1);
	bool *getting = reinterpret_cast<bool*>(emptyItems + 1);
	
	RedBlackNode<MemorySize> *node;
	if(emptyItem->removeFirstNode(&node)){
		// TODO: deal with failure
	}
	if(!(*getting)){
		emptyItems->
	}
	UnsignedInteger address(reinterpret_cast<ULONG>(addr));
	
	return true;
}

CALLCONV bool setFreeDMA(void *addr, UnsignedInteger numPages){
	Buddy<0x100,9> *dma = (Buddy<0x100,9>*)MEMORY_STRUCTURE;
	Buddy<0x100,19> *main = (Buddy<0x100,19>*)(MEMORY_STRUCTURE +
			sizeof(Buddy<0x100,9>));
	RedBlackTree<MemorySize> *dmaBusy = (RedBlackTree<MemorySize>*)(
			MEMORY_STRUCTURE + sizeof(Buddy<0x100,9>) +
			sizeof(Buddy<0x100,19>));
	RedBlackTree<MemorySize> *mainBusy = dmaBusy + 1;
	LinkedList<UINT8> *emptyItems = reinterpret_cast<LinkedList<UINT8>*>(
			mainBusy + 1);
	bool *getting = reinterpret_cast<bool*>(emptyItems + 1);
	
	UnsignedInteger address(reinterpret_cast<ULONG>(addr));
	
	return true;
}

CALLCONV bool setBusyMain(void *addr, UnsignedInteger numPages){
	Buddy<0x100,9> *dma = (Buddy<0x100,9>*)MEMORY_STRUCTURE;
	Buddy<0x100,19> *main = (Buddy<0x100,19>*)(MEMORY_STRUCTURE +
			sizeof(Buddy<0x100,9>));
	RedBlackTree<MemorySize> *dmaBusy = (RedBlackTree<MemorySize>*)(
			MEMORY_STRUCTURE + sizeof(Buddy<0x100,9>) +
			sizeof(Buddy<0x100,19>));
	RedBlackTree<MemorySize> *mainBusy = dmaBusy + 1;
	LinkedList<UINT8> *emptyItems = reinterpret_cast<LinkedList<UINT8>*>(
			mainBusy + 1);
	bool *getting = reinterpret_cast<bool*>(emptyItems + 1);
	
	UnsignedInteger address(reinterpret_cast<ULONG>(addr));
	
	return true;
}

CALLCONV bool setFreeMain(void *addr, UnsignedInteger numPages){
	Buddy<0x100,9> *dma = (Buddy<0x100,9>*)MEMORY_STRUCTURE;
	Buddy<0x100,19> *main = (Buddy<0x100,19>*)(MEMORY_STRUCTURE +
			sizeof(Buddy<0x100,9>));
	RedBlackTree<MemorySize> *dmaBusy = (RedBlackTree<MemorySize>*)(
			MEMORY_STRUCTURE + sizeof(Buddy<0x100,9>) +
			sizeof(Buddy<0x100,19>));
	RedBlackTree<MemorySize> *mainBusy = dmaBusy + 1;
	LinkedList<UINT8> *emptyItems = reinterpret_cast<LinkedList<UINT8>*>(
			mainBusy + 1);
	bool *getting = reinterpret_cast<bool*>(emptyItems + 1);
	
	UnsignedInteger address(reinterpret_cast<ULONG>(addr));
	
	return true;
}

void initBuddy(){
	Buddy<0x100,9> *dma = (Buddy<0x100,9>*)MEMORY_STRUCTURE;
	Buddy<0x100,19> *main = (Buddy<0x100,19>*)(MEMORY_STRUCTURE +
			sizeof(Buddy<0x100,9>));
	RedBlackTree<MemorySize> *dmaBusy = (RedBlackTree<MemorySize>*)(
			MEMORY_STRUCTURE + sizeof(Buddy<0x100,9>) +
			sizeof(Buddy<0x100,19>));
	RedBlackTree<MemorySize> *mainBusy = dmaBusy + 1;
	LinkedList<UINT8> *emptyItems = reinterpret_cast<LinkedList<UINT8>*>(
			mainBusy + 1);
	bool *getting = reinterpret_cast<bool*>(emptyItems + 1);
	*getting = false;
	
	UsedMemory *usedMemory0 = (UsedMemory*)KERNEL_MEMORY_RECORD0;
	
	LinkedListNode<UINT8> *emptyItem0 = reinterpret_cast<
			LinkedListNode<UINT8>*>(usedMemory0->getItem(1));
	dma->initialize(isFree, setBusyDMA, setFreeDMA);
	main->initialize(isFree, setBusyMain, setFreeMain);
	emptyItem0->initialize(0);
	emptyItems->initialize(emptyItem0);
	usedMemory0->initialize();
}
